package com.wang.gulimall.order.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradeCloseRequest;
import com.alipay.api.response.AlipayTradeCloseResponse;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rabbitmq.tools.json.JSONUtil;
import com.wang.common.constant.OrderConstant;
import com.wang.common.exception.NoStockException;
import com.wang.common.to.OrderTo;
import com.wang.common.to.mq.SeckillOrderTo;
import com.wang.common.utils.PageUtils;
import com.wang.common.utils.Query;
import com.wang.common.utils.R;
import com.wang.common.vo.MemberResponseVo;
import com.wang.gulimall.order.constant.PayConstant;
import com.wang.gulimall.order.dao.OrderDao;
import com.wang.gulimall.order.entity.OrderEntity;
import com.wang.gulimall.order.entity.OrderItemEntity;
import com.wang.gulimall.order.entity.PaymentInfoEntity;
import com.wang.gulimall.order.enume.OrderStatusEnum;
import com.wang.gulimall.order.feign.CartFeignService;
import com.wang.gulimall.order.feign.MemberFeignService;
import com.wang.gulimall.order.feign.ProductFeignService;
import com.wang.gulimall.order.feign.WareFeignService;
import com.wang.gulimall.order.interceptor.LoginUserInterceptor;
import com.wang.gulimall.order.service.OrderItemService;
import com.wang.gulimall.order.service.OrderService;
import com.wang.gulimall.order.service.PaymentInfoService;
import com.wang.gulimall.order.to.OrderCreateTo;
import com.wang.gulimall.order.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


@Service("orderService")
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {


    private ThreadLocal<OrderSubmitVo> confirmVoThreadLocal = new ThreadLocal<>();

    @Autowired
    private MemberFeignService memberFeignService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private ThreadPoolExecutor executor;    //自定义线程池

    @Autowired
    private CartFeignService cartFeignService;

    @Autowired
    private WareFeignService wmsFeignService;

    @Autowired
    private ProductFeignService productFeignService;

    @Autowired
    private OrderItemService orderItemService;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private PaymentInfoService paymentInfoService;


    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public OrderConfirmVo confirmOrder() throws ExecutionException, InterruptedException {

        //构建OrderConfirmVo
        OrderConfirmVo confirmVo = new OrderConfirmVo();

        //获取当前用户登录的信息
        MemberResponseVo memberResponseVo = LoginUserInterceptor.thread.get();
        Long memberId = memberResponseVo.getId();

        //TODO :获取当前线程请求头信息(解决Feign异步调用丢失请求头问题)
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

        //异步编排采用threadlocal出现问题， 同时feign远程调用丢失请求头的问题
        //开启第一个异步任务
        CompletableFuture<Void> addressFuture = CompletableFuture.runAsync(() -> {

            //每一个线程都来共享之前的请求数据
            RequestContextHolder.setRequestAttributes(requestAttributes);

            //1、远程查询所有的收获地址列表
            log.error("远程查询所有的收获地址列表");
            List<MemberAddressVo> address = memberFeignService.getMemberAddressList(memberResponseVo.getId());
            confirmVo.setMemberAddressVos(address);
        }, executor);

        //开启第二个异步任务
        CompletableFuture<Void> cartInfoFuture = CompletableFuture.runAsync(() -> {
            //每一个线程都来共享之前的请求数据
            RequestContextHolder.setRequestAttributes(requestAttributes);
            //2、远程查询购物车所有选中的购物项
            log.error("远程查询购物车所有选中的购物项");
            List<OrderItemVo> currentCartItems = cartFeignService.getCurrentCartItems();
            confirmVo.setItems(currentCartItems);
            //feign在远程调用之前要构造请求，调用很多的拦截器
        }, executor).thenRunAsync(() -> {
            List<OrderItemVo> items = confirmVo.getItems();
            //获取全部商品的id
            List<Long> skuIds = items.stream()
                    .map((itemVo -> itemVo.getSkuId()))
                    .collect(Collectors.toList());
            //远程查询商品库存信息
            R skuHasStock = wmsFeignService.getSkuHasStock(skuIds);
            List<SkuStockVo> skuStockVos = skuHasStock.getData("data", new TypeReference<List<SkuStockVo>>() {});
            if (skuStockVos != null && skuStockVos.size() > 0) {
                //将skuStockVos集合转换为map
                Map<Long, Boolean> skuHasStockMap = skuStockVos.stream().collect(Collectors.toMap(SkuStockVo::getSkuId, SkuStockVo::getHasStock));
                confirmVo.setStocks(skuHasStockMap);
            }
        },executor);

        //3、查询用户积分
        Integer integration = memberResponseVo.getIntegration();
        confirmVo.setIntegration(integration);

        //4、价格数据自动计算

        //TODO 5、防重令牌(防止表单重复提交)
        //为用户设置一个token，三十分钟过期时间（存在redis）
        log.error("为用户设置一个token，三十分钟过期时间（存在redis）");
        String token = UUID.randomUUID().toString().replace("-", "");
        //String token = "123456";
        stringRedisTemplate.opsForValue().set(OrderConstant.getOrderToken(memberId)+token,token,30, TimeUnit.MINUTES);
        confirmVo.setOrderToken(token);

        CompletableFuture.allOf(addressFuture,cartInfoFuture).get();

        return confirmVo;
    }

  /*  //用户订单确认页面返回数据
    @Override
    public OrderConfirmVo confirmOrder() throws ExecutionException, InterruptedException {

        OrderConfirmVo confirmVo = new OrderConfirmVo();

        // threadlocal获取当前线程对象的用户信息
        MemberResponseVo loginMember = LoginUserInterceptor.thread.get();
        Long memberId = loginMember.getId();

        //主线程的threadLocal信息
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

        List<MemberAddressVo> addressVos = memberFeignService.getMemberAddressList(memberId);
        confirmVo.setMemberAddressVos(addressVos);

        //List<OrderItemVo> checkItems = cartFeignService.getCurrentCartItems();


//        // 异步获取收货地址列表 远程调用
//        CompletableFuture<Void> addressFuture = CompletableFuture.runAsync(() -> {
//            // 线程共享
//            RequestContextHolder.setRequestAttributes(requestAttributes);
//            // 远程查询用户所有收货地址列表
//            List<MemberAddressVo> addressVos = memberFeignService.getMemberAddressList(memberId);
//            confirmVo.setMemberAddressVos(addressVos);
//
//        }, executor);
//
//        // 异步获取购物项列表 远程调用获取购物车中选中物品
//        CompletableFuture<Void> itemFuture = CompletableFuture.runAsync(() -> {
//            // 线程共享
//            RequestContextHolder.setRequestAttributes(requestAttributes);
//            // 远程查询用户选中的购物车项
//            List<OrderItemVo> checkItems = cartFeignService.getCheckItems(memberId);
//            confirmVo.setItems(checkItems);
//            // 计算订单总价
//            BigDecimal totalPrice = new BigDecimal(0);
//            int count = 0;
//            for (OrderItemVo checkItem : checkItems) {
//                totalPrice = totalPrice.add(checkItem.getTotalPrice());
//                count += checkItem.getCount();
//            }
//            // 设置其他属性
////            confirmVo.setCount(count);
////            confirmVo.setTotalPrice(totalPrice);
////            // TODO 计算减免价格
////            confirmVo.setPayPrice(totalPrice);
//
//        }, executor).thenRunAsync(() -> {
//            // 获取购物项列表
//            List<OrderItemVo> items = confirmVo.getItems();
//            // 获取购物项的skuId集合
//            List<Long> skuIds = items.stream().map(item -> item.getSkuId()).collect(Collectors.toList());
//            // 远程调用查询库存信息
//            List<HasStockTo> hasStockTos = wareFeignService.hasStock(skuIds);
//            // 将每件的sku是否含有库存封装成map形式，key为skuId，value为是否含有库存
//            Map<Long, Boolean> map = hasStockTos.stream().collect(Collectors.toMap(HasStockTo::getSkuId, HasStockTo::getHasStock));
//            confirmVo.setStocks(map);
//
//        },executor);
//
//        // 等待两个任务完成
//        CompletableFuture.allOf(addressFuture,itemFuture).get();

        // 获取用户的积分信息
        confirmVo.setIntegration(loginMember.getIntegration());

        // 随时生成一个token
        //String token = UUID.randomUUID().toString().replaceAll("-", "");
        String token = "123456";
        confirmVo.setOrderToken(token);
        log.error(token);
        // 存储到服务器  key = prefix + userId + token   value = token
        // order:token:2:b76c06d2e4d5418d87d65c3add6cffbf
        //order:token:2:123456
        stringRedisTemplate.opsForValue().set(OrderConstant.getOrderToken(memberId) + token, token, 10, TimeUnit.MINUTES);
        return confirmVo;

    }*/

    @Override
    public OrderConfirmVo getConfirmOrder() throws ExecutionException, InterruptedException {
        return null;
    }

    //创建订单
    @Override
    @Transactional
    //@GlobalTransactional  //分布式事务 缺陷是在分布式的环境中下串行化导致性能较差
    public SubmitOrderResponseVo createSubmitOrder(OrderSubmitVo vo) throws ExecutionException, InterruptedException {

        confirmVoThreadLocal.set(vo);
        // 返回值对象
        SubmitOrderResponseVo responseVo = new SubmitOrderResponseVo();

        // 获取当前线程对象的用户信息
        MemberResponseVo loginMember = LoginUserInterceptor.thread.get();
        responseVo.setCode(0);
        Long memberId = loginMember.getId();

        // 1.验证令牌是否合法【对比和删除必须保持原子性】，使用lua脚本执行验证与删除
        // lua脚本 0删除失败，1业务成功
        String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
        //前端页面提交的用户token令牌
        String orderToken = vo.getOrderToken();
        //order:token:2:123456
        String tokenKey = OrderConstant.getOrderToken(memberId) + orderToken;
        
        String redisToken = stringRedisTemplate.opsForValue().get(OrderConstant.getOrderToken(memberId));
        log.error("执行脚本，获取返回值结果");
        // 执行脚本，获取返回值结果
        Long res = stringRedisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class),
                Arrays.asList(tokenKey), orderToken);

        if (res == 0L) {
            // 验证失败
            log.error("原子令牌验证失败");
            responseVo.setCode(1);
            return responseVo;
        } else {
            // 2.令牌验证成功，创建订单
            OrderCreateTo order = createOrder();
            // 3.验证用户提交的价格和实际计算购物车选中的购物项总价是否有出入
            //前端计算用户提交的总价，是加了运费的
            BigDecimal userSubmitPrice = vo.getPayPrice();

            BigDecimal fare = order.getFare();     //运费
            BigDecimal payPrice = order.getPayPrice();//后端计算运费
            //前端没有计算运费
            BigDecimal subtract = userSubmitPrice.subtract(fare);
            if (Math.abs(subtract.subtract(payPrice).doubleValue()) == 0.01) {
                // 验价失败
                log.error("前端提交验价格失败");
                responseVo.setCode(2);
                return responseVo;
            } else {
                //令牌验证成功
                //1、创建订单、订单项等信息
                //金额对比
                //TODO 3、保存订单
                log.error("保存订单");
                saveOrder(order);
                log.error("保存订单成功");

                //4、库存锁定,只要有异常，回滚订单数据 开始事务
                //订单号、所有订单项信息(skuId,skuNum,skuName)
                WareSkuLockVo lockVo = new WareSkuLockVo();
                lockVo.setOrderSn(order.getOrder().getOrderSn());

                //获取出要锁定的商品数据信息
                List<OrderItemVo> orderItemVos = order.getOrderItems().stream().map((item) -> {
                    OrderItemVo orderItemVo = new OrderItemVo();
                    orderItemVo.setSkuId(item.getSkuId());
                    orderItemVo.setCount(item.getSkuQuantity());
                    orderItemVo.setTitle(item.getSkuName());
                    return orderItemVo;
                }).collect(Collectors.toList());
                lockVo.setLocks(orderItemVos);

                //TODO 调用远程锁定库存的方法
                //出现的问题：扣减库存成功了，但是由于网络原因超时，出现异常，导致订单事务回滚，库存事务不回滚(解决方案：seata)
                //为了保证高并发，不推荐使用seata，因为是加锁，并行化，提升不了效率,可以发消息给库存服务
                log.error("锁定库存");
                R r = wmsFeignService.orderLockStock(lockVo);
                if (r.getCode() == 0) {
                    //锁定成功
                    log.error("订单服务锁定库存成功");
                    responseVo.setOrder(order.getOrder());
                    //int i = 10 / 0;

                    //TODO 远程扣减会员积分

                    //TODO 订单创建成功，发送消息给MQ 实现定时关闭订单功能30分钟之后定时关闭订单
                    rabbitTemplate.convertAndSend("order-event-exchange", "order.create.order", order.getOrder());
                    //删除购物车里的数据
                    //stringRedisTemplate.delete(CART_PREFIX+memberResponseVo.getId());
                    return responseVo;
                } else {
                    //锁定失败  1.若锁定库存出现异常的话 订单数据全部回滚
                    String msg = (String) r.get("msg");
                    throw new NoStockException(msg);
                }
            }
        }
    }

    /**
     * 保存订单所有数据
     *
     * @param orderCreateTo
     */
    private void saveOrder(OrderCreateTo orderCreateTo) {

        //获取订单信息
        OrderEntity order = orderCreateTo.getOrder();
        order.setModifyTime(new Date());
        order.setCreateTime(new Date());
        //保存订单
        this.baseMapper.insert(order);

        //获取订单项信息
        List<OrderItemEntity> orderItems = orderCreateTo.getOrderItems();
        //批量保存订单项数据
        boolean batch = orderItemService.saveBatch(orderItems);
        if (batch) {
            System.out.println("批量保存成功");
        }
    }


    /**
     * 创建订单     TODO 已经初步优化
     *
     * @return
     */
    private OrderCreateTo createOrder() throws ExecutionException, InterruptedException {
        OrderCreateTo createTo = new OrderCreateTo();

        //1、生成订单号  202106180918302291405696388406706177
        // idworker是一个ID生成工具，可以生成一个全局唯一的长整形ID。也支持分布式环境下的使用。idworker采用了Snowflake算法
        String orderSn = IdWorker.getTimeId();
        OrderEntity orderEntity = builderOrder(orderSn);

        //2、获取到所有的订单项
        List<OrderItemEntity> orderItemEntities = builderOrderItems(orderSn);

        //3、验价(计算价格、积分等信息)
        computePrice(orderEntity, orderItemEntities);

        createTo.setOrder(orderEntity);
        createTo.setOrderItems(orderItemEntities);

        createTo.setFare(orderEntity.getFreightAmount());
        createTo.setPayPrice(orderEntity.getTotalAmount());

        return createTo;

    }

    /**
     * 构建订单数据
     *
     * @param orderSn
     * @return
     */
    private OrderEntity builderOrder(String orderSn) {

        //获取当前用户登录信息
        MemberResponseVo memberResponseVo = LoginUserInterceptor.thread.get();

        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setMemberId(memberResponseVo.getId());
        orderEntity.setOrderSn(orderSn);
        orderEntity.setMemberUsername(memberResponseVo.getUsername());

        //前端传输数据
        //OrderSubmitVo(addrId=2, payType=null, orderToken=123456, payPrice=100, node=测试)
        OrderSubmitVo orderSubmitVo = confirmVoThreadLocal.get();

        //远程获取收货地址和运费信息
        R fareAddressVo = wmsFeignService.getFare(orderSubmitVo.getAddrId());
        FareVo fareResp = fareAddressVo.getData("data", new TypeReference<FareVo>() {
        }); // 收获地址 邮费

        //获取到运费信息
        BigDecimal fare = fareResp.getFare();
        orderEntity.setFreightAmount(fare);

        //获取到收货地址信息
        MemberAddressVo address = fareResp.getAddress();
        //设置收货人信息
        orderEntity.setReceiverName(address.getName());
        orderEntity.setReceiverPhone(address.getPhone());
        orderEntity.setReceiverPostCode(address.getPostCode());
        orderEntity.setReceiverProvince(address.getProvince());
        orderEntity.setReceiverCity(address.getCity());
        orderEntity.setReceiverRegion(address.getRegion());
        orderEntity.setReceiverDetailAddress(address.getDetailAddress());

        //设置订单相关的状态信息
        orderEntity.setStatus(OrderStatusEnum.CREATE_NEW.getCode());
        orderEntity.setAutoConfirmDay(7);
        orderEntity.setConfirmStatus(0);
        return orderEntity;
    }

    /**
     * 构建所有订单项数据
     *
     * @return
     */
    public List<OrderItemEntity> builderOrderItems(String orderSn) {

        List<OrderItemEntity> orderItemEntityList = new ArrayList<>();

        //最后确定每个购物项的价格
        List<OrderItemVo> currentCartItems = cartFeignService.getCurrentCartItems();
        if (currentCartItems != null && currentCartItems.size() > 0) {
            orderItemEntityList = currentCartItems.stream().map((items) -> {
                //构建订单项数据
                OrderItemEntity orderItemEntity = builderOrderItem(items);
                orderItemEntity.setOrderSn(orderSn);
                return orderItemEntity;
            }).collect(Collectors.toList());
        }

        return orderItemEntityList;
    }

    /**
     * 构建某一个订单项的数据
     *
     * @param items
     * @return
     */
    private OrderItemEntity builderOrderItem(OrderItemVo items) {

        OrderItemEntity orderItemEntity = new OrderItemEntity();

        //1、商品的spu信息
        Long skuId = items.getSkuId();
        //获取spu的信息
        R spuInfo = productFeignService.getSpuInfoBySkuId(skuId);
        SpuInfoVo spuInfoData = spuInfo.getData("data", new TypeReference<SpuInfoVo>() {
        });
        orderItemEntity.setSpuId(spuInfoData.getId());
        orderItemEntity.setSpuName(spuInfoData.getSpuName());
        orderItemEntity.setSpuBrand(spuInfoData.getBrandId().toString());
        orderItemEntity.setCategoryId(spuInfoData.getCatalogId());

        //2、商品的sku信息
        orderItemEntity.setSkuId(skuId);
        orderItemEntity.setSkuName(items.getTitle());
        orderItemEntity.setSkuPic(items.getImage());
        orderItemEntity.setSkuPrice(items.getPrice());
        orderItemEntity.setSkuQuantity(items.getCount());

        //使用StringUtils.collectionToDelimitedString将list集合转换为String
        String skuAttrValues = StringUtils.collectionToDelimitedString(items.getSkuAttrValues(), ";");
        orderItemEntity.setSkuAttrsVals(skuAttrValues);

        //3、商品的优惠信息

        //4、商品的积分信息
        orderItemEntity.setGiftGrowth(items.getPrice().multiply(new BigDecimal(items.getCount())).intValue());
        orderItemEntity.setGiftIntegration(items.getPrice().multiply(new BigDecimal(items.getCount())).intValue());

        //5、订单项的价格信息
        orderItemEntity.setPromotionAmount(BigDecimal.ZERO);
        orderItemEntity.setCouponAmount(BigDecimal.ZERO);
        orderItemEntity.setIntegrationAmount(BigDecimal.ZERO);

        //当前订单项的实际金额.总额 - 各种优惠价格
        //原来的价格
        BigDecimal origin = orderItemEntity.getSkuPrice().multiply(new BigDecimal(orderItemEntity.getSkuQuantity().toString()));
        //原价减去优惠价得到最终的价格
        BigDecimal subtract = origin.subtract(orderItemEntity.getCouponAmount())
                .subtract(orderItemEntity.getPromotionAmount())
                .subtract(orderItemEntity.getIntegrationAmount());
        orderItemEntity.setRealAmount(subtract);

        return orderItemEntity;
    }

    /**
     * 计算价格的方法
     *
     * @param orderEntity
     * @param orderItemEntities
     */
    private void computePrice(OrderEntity orderEntity, List<OrderItemEntity> orderItemEntities) {

        //总价
        BigDecimal total = new BigDecimal("0.0");
        //优惠价
        BigDecimal coupon = new BigDecimal("0.0");
        BigDecimal intergration = new BigDecimal("0.0");
        BigDecimal promotion = new BigDecimal("0.0");

        //积分、成长值
        Integer integrationTotal = 0;
        Integer growthTotal = 0;

        //订单总额，叠加每一个订单项的总额信息
        for (OrderItemEntity orderItem : orderItemEntities) {
            //优惠价格信息
            coupon = coupon.add(orderItem.getCouponAmount());
            promotion = promotion.add(orderItem.getPromotionAmount());
            intergration = intergration.add(orderItem.getIntegrationAmount());

            //总价
            total = total.add(orderItem.getRealAmount());

            //积分信息和成长值信息
            integrationTotal += orderItem.getGiftIntegration();
            growthTotal += orderItem.getGiftGrowth();

        }
        //1、订单价格相关的
        orderEntity.setTotalAmount(total);
        //设置应付总额(总额+运费)
        orderEntity.setPayAmount(total.add(orderEntity.getFreightAmount()));
        orderEntity.setCouponAmount(coupon);
        orderEntity.setPromotionAmount(promotion);
        orderEntity.setIntegrationAmount(intergration);

        //设置积分成长值信息
        orderEntity.setIntegration(integrationTotal);
        orderEntity.setGrowth(growthTotal);

        //设置删除状态(0-未删除，1-已删除)
        orderEntity.setDeleteStatus(0);

    }


    @Override
    public Boolean cancelOrder(String orderSn) {
        return null;
    }


    @Override
    public List<OrderListVo> listMemberOrderList() {
        return null;
    }

    /**
     * 按照订单号获取订单信息
     * @param orderSn
     * @return
     */
    @Override
    public OrderEntity getOrderByOrderSn(String orderSn) {
        log.error("调用订单服务的service查询订单");
        OrderEntity orderEntity = this.baseMapper.selectOne(new QueryWrapper<OrderEntity>().eq("order_sn", orderSn));
        return orderEntity;
    }


    /**
     * 创建秒杀单
     * @param orderTo
     */
    @Override
    public void createSeckillOrder(SeckillOrderTo orderTo) {

        //TODO 保存订单信息
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setOrderSn(orderTo.getOrderSn());
        orderEntity.setMemberId(orderTo.getMemberId());
        orderEntity.setCreateTime(new Date());
        BigDecimal totalPrice = orderTo.getSeckillPrice().multiply(BigDecimal.valueOf(orderTo.getNum()));
        orderEntity.setPayAmount(totalPrice);
        orderEntity.setStatus(OrderStatusEnum.CREATE_NEW.getCode());

        //保存订单
        this.save(orderEntity);

        //保存订单项信息
        OrderItemEntity orderItem = new OrderItemEntity();
        orderItem.setOrderSn(orderTo.getOrderSn());
        orderItem.setRealAmount(totalPrice);

        orderItem.setSkuQuantity(orderTo.getNum());

        //保存商品的spu信息
        R spuInfo = productFeignService.getSpuInfoBySkuId(orderTo.getSkuId());
        SpuInfoVo spuInfoData = spuInfo.getData("data", new TypeReference<SpuInfoVo>() {
        });
        orderItem.setSpuId(spuInfoData.getId());
        orderItem.setSpuName(spuInfoData.getSpuName());
        //orderItem.setSpuBrand(spuInfoData.getBrandName());
        orderItem.setCategoryId(spuInfoData.getCatalogId());

        //保存订单项数据
        orderItemService.save(orderItem);
    }


    /**
     * 获取当前订单的支付信息
     * @param orderSn
     * @return
     */
    @Override
    public PayVo getOrderPay(String orderSn) {
        PayVo payVo = new PayVo();
        //订单总表根据订单号查询订单
        OrderEntity orderInfo = this.getOrderByOrderSn(orderSn);

        //保留两位小数点，向上取值
        BigDecimal payAmount = orderInfo.getPayAmount().setScale(2, BigDecimal.ROUND_UP);
        //付款金额
        payVo.setTotal_amount(payAmount.toString());
        //商户订单号
        payVo.setOut_trade_no(orderInfo.getOrderSn());

        //查询订单项的数据
        List<OrderItemEntity> orderItemInfo = orderItemService.list(
                new QueryWrapper<OrderItemEntity>().eq("order_sn", orderSn));
        OrderItemEntity orderItemEntity = orderItemInfo.get(0);
        payVo.setBody(orderItemEntity.getSkuAttrsVals());
        payVo.setSubject(orderItemEntity.getSkuName());
        return payVo; //订单总额+订单编号
    }

    /**
     * 查询当前用户所有订单数据
     * @param params
     * @return
     */
    @Override
    public PageUtils queryPageWithItem(Map<String, Object> params) {

        MemberResponseVo memberResponseVo = LoginUserInterceptor.thread.get();

        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
                        .eq("member_id",memberResponseVo.getId()).orderByDesc("create_time")
        );

        //遍历所有订单集合
        List<OrderEntity> orderEntityList = page.getRecords().stream().map(order -> {
            //根据订单号查询订单项里的数据
            List<OrderItemEntity> orderItemEntities = orderItemService.list(new QueryWrapper<OrderItemEntity>()
                    .eq("order_sn", order.getOrderSn()));
            order.setOrderItemEntityList(orderItemEntities);
            return order;
        }).collect(Collectors.toList());
        page.setRecords(orderEntityList);
        return new PageUtils(page);
    }


    /**
     * 处理支付宝的支付结果 本服务事务
     * @param asyncVo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String handleAliPay(PayAsyncVo asyncVo) {
        //1.保存交易流水信息
        PaymentInfoEntity paymentInfo = new PaymentInfoEntity();
        paymentInfo.setOrderSn(asyncVo.getOut_trade_no());//订单号   202106230939126821407513538956181506 我系统里面的
        paymentInfo.setAlipayTradeNo(asyncVo.getTrade_no());//流水号 2021062322001454010500987410
        paymentInfo.setTotalAmount(new BigDecimal(asyncVo.getBuyer_pay_amount())); //支付总金额
        paymentInfo.setSubject(asyncVo.getBody());//交易内容
        paymentInfo.setPaymentStatus(asyncVo.getTrade_status());//交易状态 TRADE_SUCCESS
        paymentInfo.setCreateTime(new Date());
        paymentInfo.setCallbackTime(asyncVo.getNotify_time());
        //添加到数据库中
        this.paymentInfoService.save(paymentInfo);
        //2.修改订单状态
        //获取当前状态
        String tradeStatus = asyncVo.getTrade_status();
        //支付宝服务器的订单状态已经改变了,我们需要修改系统的订单order状态信息 支付宝异步回调的保障幂等性问题需要考虑
        if (tradeStatus.equals("TRADE_SUCCESS") || tradeStatus.equals("TRADE_FINISHED")) {
            //支付成功状态
            String orderSn = asyncVo.getOut_trade_no(); //获取本地系统的order订单号
            //修改订单状态 修改订单状态为    PAYED(1,"已付款"),
            this.updateOrderStatus(orderSn,OrderStatusEnum.PAYED.getCode(), PayConstant.ALIPAY);
        }
        return "success";
    }

    @Override
    public void alipayCloseOrder(OrderEntity orderEntity) throws AlipayApiException {
    }

    /**
     * 修改订单状态
     * @param orderSn
     * @param code
     */
    private void updateOrderStatus(String orderSn, Integer code,Integer payType) {
        this.baseMapper.updateOrderStatus(orderSn,code,payType);
    }


    //订单服务定时关闭功能 关闭订单成功给MQ发送消息 同时库存服务解锁库存主动方式
    @Override
    public void closeOrder(OrderEntity orderEntity) {

        //关闭订单之前先查询一下数据库，判断此订单状态是否已支付
        OrderEntity orderInfo = this.getOne(new QueryWrapper<OrderEntity>().
                eq("order_sn",orderEntity.getOrderSn()));

        //订单的4种状态：订单状态【0->待付款；1->待发货；2->已发货；3->已完成；4->已关闭；5->无效订单】

        // 订单状态还是代付款状态 CREATE_NEW(0,"待付款"),
        if (orderInfo.getStatus().equals(OrderStatusEnum.CREATE_NEW.getCode())) {
            //代付款状态进行关单
            OrderEntity orderUpdate = new OrderEntity();
            orderUpdate.setId(orderInfo.getId());
            // 订单状态【0->待付款；1->待发货；2->已发货；3->已完成；4->已关闭；5->无效订单】
            //将订单状态修改为关闭状态
            orderUpdate.setStatus(OrderStatusEnum.CANCLED.getCode());
            this.updateById(orderUpdate);

            // 发送消息给MQ 30分钟后关闭订单成功此时需要解锁库存
            OrderTo orderTo = new OrderTo();
            BeanUtils.copyProperties(orderInfo, orderTo);

            try {
                //TODO 确保每个消息发送成功，给每个消息做好日志记录，(给数据库保存每一个详细信息)保存每个消息的详细信息
                log.error("订单服务主动解锁成功,发送解锁的订单号给库存服务{}"+orderTo.getOrderSn());
                rabbitTemplate.convertAndSend("order-event-exchange", "order.release.other", orderTo);
            } catch (Exception e) {
                //TODO 定期扫描数据库，重新发送失败的消息
            }
        }
    }
}